package cn.jimmie.learn.viewArt.ball;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

import cn.jimmie.learn.viewArt.R;


/**
 * function : 浮白视图, 只负责绘制
 *
 * <p> Create Time: 2018年12月31日 09:17 </p>
 * <p> @author Jimmie.Qian  </p>
 */
@SuppressLint("ViewConstructor")
class AssistPopBaseView extends View {
    private static String LINE_TEXT;
    private static String NEXT_TEXT;

    final Paint mPaint;
    final Conf mConf;
    final Padding mPadding;
    private final RectF mBgRect = new RectF();
    private final Path mArrowPath = new Path();
    // 三个可响应点击的区域
    private final Rect mCloseRect = new Rect();
    private final Rect mLinkRect = new Rect();
    private final Rect mNextRect = new Rect();
    AssistBall.Message mMessage;
    private int mCursor;
    private AssistBall.OnAssistPopEventListener mListener;

    AssistPopBaseView(Context context, Conf conf) {
        super(context);
        this.mConf = conf;
        mPadding = new Padding();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);

        NEXT_TEXT = context.getResources().getString(R.string.m4399_ope_assist_pop_next);
        LINE_TEXT = context.getResources().getString(R.string.m4399_ope_assist_pop_link);
    }

    static Builder creator(Context ctx) {
        return new Builder(ctx);
    }

    static void measureTitle(AssistBall.Message message, Conf.Dimen dimen) {
        message.titleHeight = message.title.isEmpty() ? 0 : dimen.titleMargin + dimen.titleTs;
    }

    // ===================== 绘制相关 ========================

    static void measureLines(AssistBall.Message message, Paint paint, Conf.Dimen dimen) {
        message.contentLines = message.enableContentClick ? measureLinkLines(message, paint, dimen.maxLineSize) :
            measureNoneLinkLines(message, paint, dimen.maxLineSize);
        int len = message.contentLines.length;
        message.textUnit = dimen.contentTs + dimen.contentMargin;
        message.contentHeight = dimen.contentTs * len + dimen.contentMargin * (len - 1);
    }

    private static String[] measureNoneLinkLines(AssistBall.Message message, Paint paint, int maxSize) {
        List<String> list = new ArrayList<>();
        float realSize;
        int lastIndex = message.content.length();
        int startIndex = 0;
        for (; startIndex < lastIndex; lastIndex--) {
            realSize = paint.measureText(message.content, startIndex, lastIndex);
            if (realSize <= maxSize) {
                list.add(message.content.substring(startIndex, lastIndex));
                startIndex = lastIndex;
                lastIndex = message.content.length();
            }
        }
        String[] arr = new String[list.size()];
        for (int i = 0; i < list.size(); i++) {
            arr[i] = list.get(i);
        }
        list.clear();
        return arr;
    }

    private static String[] measureLinkLines(AssistBall.Message message, Paint paint, int maxSize) {
        String[] arr = measureNoneLinkLines(message, paint, maxSize);
        if (arr.length == 0) return arr;
        String lastLine = arr[arr.length - 1];
        float realSize = paint.measureText(lastLine + LINE_TEXT);
        if (realSize < maxSize) arr[arr.length - 1] = lastLine + LINE_TEXT;
        else {
            String[] old = arr;
            arr = new String[old.length + 1];
            System.arraycopy(old, 0, arr, 0, old.length);
            arr[old.length] = LINE_TEXT;
        }
        return arr;
    }

    void setListener(AssistBall.OnAssistPopEventListener listener) {
        mListener = listener;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mMessage == null) return;
        // 绘制背景
        drawBg(canvas);
        // 头部间距
        mCursor = mConf.DIMEN.frameMargin + mPadding.top;
        // 绘制title
        drawTitle(canvas);
        // 绘制内容
        drawContent(canvas);
        // 绘制关闭按钮
        drawClose(canvas);
        // 绘制下一条
        drawNext(canvas);
    }

    private void drawBg(Canvas canvas) {
        // 绘制背景
        setBgStyle();
        mBgRect.set(mPadding.left, mPadding.top, getWidth() - mPadding.right, getHeight() - mPadding.bottom);
        canvas.drawRoundRect(mBgRect, mConf.DIMEN.arrowWidth, mConf.DIMEN.arrowWidth, mPaint);

        // 绘制箭头
        float x = mPadding.pctX * getWidth();
        float y = mPadding.pctY * getHeight();
        float x1, x2, y1, y2;
        if (mPadding.type == AssistBallView.RIGHT) {
            x = getWidth();
            x1 = x2 = x - mConf.DIMEN.arrowWidth;
            y1 = y - (mConf.DIMEN.arrowSize >> 1);
            y2 = y + (mConf.DIMEN.arrowSize >> 1);
        } else if (mPadding.type == AssistBallView.LEFT) {
            x = 0;
            x1 = x2 = x + mConf.DIMEN.arrowWidth;
            y1 = y - (mConf.DIMEN.arrowSize >> 1);
            y2 = y + (mConf.DIMEN.arrowSize >> 1);
        } else if (mPadding.type == AssistBallView.TOP) {
            y = 0;
            y1 = y2 = y + mConf.DIMEN.arrowWidth;
            x1 = x - (mConf.DIMEN.arrowSize >> 1);
            x2 = x + (mConf.DIMEN.arrowSize >> 1);
        } else {
            y = getHeight();
            y1 = y2 = y - mConf.DIMEN.arrowWidth;
            x1 = x - (mConf.DIMEN.arrowSize >> 1);
            x2 = x + (mConf.DIMEN.arrowSize >> 1);
        }
        mArrowPath.reset();
        mArrowPath.moveTo(x, y);
        mArrowPath.lineTo(x1, y1);
        mArrowPath.lineTo(x2, y2);
        mArrowPath.close();
        canvas.drawPath(mArrowPath, mPaint);
    }

    // =========== 设置画笔风格 ======================

    private void drawTitle(Canvas canvas) {
        if (mMessage.title.isEmpty()) return;
        setTitleStyle();
        int y = mCursor + mConf.DIMEN.titleTs;
        canvas.drawText(mMessage.title, mConf.DIMEN.frameMargin + mPadding.left, y, mPaint);
        // 绘制下一个边距
        mCursor = mConf.DIMEN.titleMargin + y;
    }

    private void drawContent(Canvas canvas) {
        if (mMessage.title.isEmpty()) {
            mCursor = (int) (mCursor * 1.5);
        }
        setContentStyle();
        // 字体的底部位置
        int bottomY;

        String[] lines = mMessage.contentLines;
        for (int i = 0; i < lines.length - 1; i++) {
            String line = lines[i];
            bottomY = mCursor + mConf.DIMEN.contentTs;
            canvas.drawText(line, mConf.DIMEN.frameMargin + mPadding.left, bottomY, mPaint);
            mCursor = bottomY + mConf.DIMEN.contentMargin;
        }
        if (lines.length == 0) return;

        String lastLine = lines[lines.length - 1];
        bottomY = mCursor + mConf.DIMEN.contentTs;

        if (mMessage.enableContentClick) {
            lastLine = lastLine.substring(0, lastLine.length() - 4);
            float textCursor = mPaint.measureText(lastLine);

            setLinkStyle();
            canvas.drawText(LINE_TEXT, mConf.DIMEN.frameMargin + textCursor + mPadding.left, bottomY, mPaint);
            // 设置链接的点击区域
            int left = (int) (mConf.DIMEN.frameMargin + textCursor + mPadding.left);
            int right = (int) (left + mPaint.measureText(LINE_TEXT));
            // 左右下扩大点击范围
            mLinkRect.set(left - mConf.DIMEN.clickableEdge, mCursor,
                right + mConf.DIMEN.clickableEdge, bottomY + mConf.DIMEN.clickableEdge);
        }

        setContentStyle();
        canvas.drawText(lastLine, mConf.DIMEN.frameMargin + mPadding.left, bottomY, mPaint);
        mCursor = bottomY + mConf.DIMEN.contentMargin;
    }

    private void drawClose(Canvas canvas) {
        int left = getWidth() - mConf.DIMEN.closeMargin * 2 - mPadding.right;
        int top = mConf.DIMEN.closeMargin + mPadding.top;
        int right = getWidth() - mConf.DIMEN.closeMargin - mPadding.right;
        int bottom = mConf.DIMEN.closeMargin * 2 + mPadding.top;
        Drawable drawable = mConf.RES.closeDw;
        drawable.setBounds(left, top, right, bottom);
        // 扩大点击范围
        mCloseRect.set(left - mConf.DIMEN.clickableEdge, top - mConf.DIMEN.clickableEdge,
            right + mConf.DIMEN.clickableEdge, bottom + mConf.DIMEN.clickableEdge);
        drawable.draw(canvas);
    }

    private void drawNext(Canvas canvas) {
        if (!hasNext()) return;
        @SuppressLint("DefaultLocale")
        String text = String.format(NEXT_TEXT, getNextCount());
        setNextStyle();
        int x = (int) (getWidth() - mPadding.right - mConf.DIMEN.nextMargin
            - mPaint.measureText(NEXT_TEXT));
        int y = mCursor + mConf.DIMEN.contentTs;
        if (getHeight() == mConf.DIMEN.minHeight) {
            y = getHeight() - mConf.DIMEN.frameMargin;
        }
        canvas.drawText(text, x, y, mPaint);
        // 设置next的点击区域
        int right = (int) (x + mPaint.measureText(text));
        // 左右上扩大点击范围`
        mNextRect.set(x - mConf.DIMEN.clickableEdge, mCursor,
            right + mConf.DIMEN.clickableEdge, y + mConf.DIMEN.clickableEdge);
    }

    private void setBgStyle() {
        mPaint.setColor(Color.WHITE);
        mPaint.setAlpha(255);
    }

    // ====================== 点击事件相关 ======================

    void setContentStyle() {
        mPaint.setColor(mConf.COLOR.content);
        mPaint.setAlpha(128);
        mPaint.setTextSize(mConf.DIMEN.contentTs);
    }

    private void setLinkStyle() {
        mPaint.setTextSize(mConf.DIMEN.contentTs);
        mPaint.setColor(mConf.COLOR.title);
        mPaint.setAlpha(255);
    }

    void setTitleStyle() {
        mPaint.setTextSize(mConf.DIMEN.titleTs);
        mPaint.setColor(mConf.COLOR.title);
        mPaint.setAlpha(255);
    }

    void setNextStyle() {
        mPaint.setColor(mConf.COLOR.next);
        mPaint.setAlpha(66);
        mPaint.setTextSize(mConf.DIMEN.contentTs);
    }

    @Override
    @SuppressLint("ClickableViewAccessibility")
    public boolean onTouchEvent(MotionEvent event) {
        if (mMessage == null) return false;
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            float x = event.getX();
            float y = event.getY();

            if (checkRect(mCloseRect, x, y)) {
                onCloseEvent(true);
            } else if (mMessage.enableContentClick && checkRect(mLinkRect, x, y)) {
                onLinkEvent();
            } else if (hasNext() && checkRect(mNextRect, x, y)) {
                onNextEvent(true);
            }
        }
        return true;
    }


    // ====================== 测量相关 ==========================

    private boolean checkRect(Rect rect, float x, float y) {
        return x > rect.left && x < rect.right
            && y > rect.top && y < rect.bottom;
    }

    void onCloseEvent(boolean byUser) {
        if (mListener != null) mListener.onPopCloseClick(byUser);
    }

    void onNextEvent(boolean byUser) {
        if (mListener != null) mListener.onPopNextClick(byUser);
    }

    private void onLinkEvent() {
        if (mListener != null) mListener.onPopContentClick();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int mode = MeasureSpec.getMode(widthMeasureSpec);
        if (mMessage == null) {
            super.onMeasure(MeasureSpec.makeMeasureSpec(0, mode),
                MeasureSpec.makeMeasureSpec(0, mode));
        } else {
            super.onMeasure(MeasureSpec.makeMeasureSpec(mConf.DIMEN.width, mode),
                MeasureSpec.makeMeasureSpec(realHeight(), mode));
        }
    }

    int realHeight() {
        if (mMessage == null) return 0;
        int height = (int) (getTextHeight() + mConf.DIMEN.frameMargin * 2);
        if (height < mConf.DIMEN.minHeight) {
            if (mMessage.title.isEmpty()) {
                height = height + mConf.DIMEN.frameMargin;
            } else height = mConf.DIMEN.minHeight;
        }
        if (mPadding.type == AssistBallView.TOP || mPadding.type == AssistBallView.BOTTOM) {
            height = height + mConf.DIMEN.arrowWidth;
        }
        return height;
    }

    boolean hasNext() {
        return false;
    }

    int getNextCount() {
        return 0;
    }

    private float getTextHeight() {
        return !hasNext() ? mMessage.contentHeight + mMessage.titleHeight
            : mMessage.contentHeight + mMessage.titleHeight + mMessage.textUnit;
    }

    // =============== padding值 ===============

    public static class Builder {
        private final Context ctx;
        private final Conf conf;

        private Builder(Context ctx) {
            this.ctx = ctx;
            conf = new Conf();
            init();
        }

        private void init() {
            final float root2 = 1.4142135623731f;
            final float dp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                1, ctx.getResources().getDisplayMetrics());
            final float sp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                1, ctx.getResources().getDisplayMetrics());
            conf.DIMEN.frameMargin = (int) (16 * dp);
            conf.DIMEN.titleMargin = (int) (10 * sp);
            conf.DIMEN.contentMargin = (int) (8 * dp);
            conf.DIMEN.closeMargin = (int) (8 * dp);
            conf.DIMEN.nextMargin = (int) (22 * dp);
            conf.DIMEN.titleTs = (int) (14 * sp);
            conf.DIMEN.contentTs = (int) (12 * sp);
            conf.DIMEN.arrowWidth = (int) (8 * dp);
            conf.DIMEN.arrowSize = (int) (conf.DIMEN.arrowWidth * root2);
            conf.DIMEN.minHeight = (int) (85 * dp);
            conf.DIMEN.width = (int) (200 * dp);
            conf.DIMEN.maxLineSize = conf.DIMEN.width - conf.DIMEN.frameMargin * 2 - conf.DIMEN.arrowWidth;
            conf.DIMEN.clickableEdge = (int) (10 * dp);

            conf.COLOR.title = Color.parseColor("#ff9515");
            conf.COLOR.content = Color.BLACK;
            conf.COLOR.next = Color.BLACK;

            conf.RES.closeDw = ContextCompat.getDrawable(ctx, R.drawable.m4399_ope_assist_pop_close);
        }

//        public AssistPopBaseView create() {
//            return new AssistPopBaseView(ctx, conf);
//        }

        Conf config() {
            return conf;
        }
    }

    // ==================== config ====================

    static class Conf {
        final Color COLOR;
        final Dimen DIMEN;
        final Res RES;

        Conf() {
            COLOR = new Color();
            DIMEN = new Dimen();
            RES = new Res();
        }

        // 颜色
        class Color {
            int title;          // 标题的颜色
            int content;        // 内容的颜色
            int next;           // 下一条的颜色
        }

        // 尺寸
        // Ts 表示文字大小尺寸
        class Dimen {
            int width;          // 控件宽度, 高度自适应,无需设置
            int minHeight;      // 最小的高度
            int frameMargin;    // 内容距离边框的尺寸
            int titleMargin;    // 标题距离其他元素的距离
            int contentMargin;  // 文字内容距离其他元素的距离
            int closeMargin;    // 关闭按钮距离边框的距离
            int nextMargin;     // 下一条按钮距离边框的距离
            int titleTs;        // 标题文字的大小
            int contentTs;      // 内容文字的大小
            int arrowWidth;     // 浮白箭头的宽度
            int arrowSize;      // 浮白的边长, 固定为箭头宽度的√2倍
            int maxLineSize;    // 单行的最大字符长度
            int clickableEdge;  // 扩大点击的范围大小
        }

        // 资源
        // Tx 表示文字
        // Dw 表示Drawable
        class Res {
            Drawable closeDw;   // 关闭按钮的资源
        }
    }

    /**
     * 用于定位 浮白的箭头处于上下左右哪个方向
     */
    class Padding {
        int left, right, top, bottom, type;
        float pctX, pctY;

        void set(int type, int value) {
            this.type = type;
            left = right = top = bottom = 0;
            if (type == AssistBallView.LEFT) left = value;
            else if (type == AssistBallView.TOP) top = value;
            else if (type == AssistBallView.BOTTOM) bottom = value;
            else right = value;
        }

        // x,y的百分比位置
        void xy(float x, float y) {
            this.pctX = x;
            this.pctY = y;
        }
    }
}
